use std::time::{Duration, Instant  };
use rpc::error::RpcError;
use rpc::{RpcChannel, RpcContext, RpcResult};
use rpc::bootstrap::BootstrapBuilder;
use rpc::connection_manager::event::{IdleListener, IdleResultData};
use rpc_client::client::RpcClientBuilder;
use rpc_derive::{router, rpc_router, rpc_service, service};
use rpc_server::server::RpcServerBuilder;

#[tokio::test]
async fn server_test_heart() -> RpcResult<()> {
    // env_logger::init();
    server_test(8681, "json", 1).await
}

async fn server_test(port: u32, codec_type: &'static str, n: u32) -> RpcResult<()>{
    tokio::spawn(async move {
        let bootstrap = BootstrapBuilder::new()
            .router("/hello", router!(hello))
            .add_idle_listener(Box::new(HeartIdleListener::new(1, 1)))
            ;
        let _ = RpcServerBuilder::new(bootstrap, port)
            .build().start_server().await;
    });

    let now = Instant::now();
    let bootstrap2 = BootstrapBuilder::new().build();
    let address = format!("127.0.0.1:{}", port);
    let rpc_client = RpcClientBuilder::new(bootstrap2, &address)
        .set_current_codec_type(codec_type)
        .build();

    let mut channel = rpc_client.connection().await?;

    let mut hello_service = service!(channel.context.clone(), HelloService);

    for i in 0..n {
        let result = hello_service.hello(&mut channel, i as i32).await;
        // info!("call result: {}, result2: {}", result, result2);
        match result {
            Ok(result) => {
                assert_eq!(result, (i+100) as i32);
            }
            Err(error) => {
                if let RpcError::CustomerError { message, ..} = error {
                    assert_eq!(message, "测试异常");
                }
            }
        }
    }

    let time = now.elapsed();
    println!("result:::::::::::::::: time: {}", time.as_millis());

    tokio::time::sleep(Duration::from_secs(61)).await;

    rpc_client.close().await?;

    tokio::time::sleep(Duration::from_secs(61)).await;
    Ok(())
}

#[rpc_router]
fn hello(context: &mut RpcContext, data: i32) -> i32 {
    let mut session = context.session();
    session.with_data("hello", |a: &mut i32| {
        println!("session value: {}", a);
        a.clone()
    });
    data + 100
}

#[rpc_service(timeout=30)]
#[async_trait::async_trait]
trait HelloService {

    #[path = "/hello"]
    async fn hello(&mut self, channel: &mut impl RpcChannel, value: i32) -> RpcResult<i32>;
}

struct HeartIdleListener {
    write_idle_time: u64,
    read_idle_time: u64,
}

impl HeartIdleListener {
    fn new(write_idle_time: u64, read_idle_time: u64) -> Self {
        Self { write_idle_time, read_idle_time }
    }
}

impl IdleListener for HeartIdleListener {
    fn get_write_idle_time(&self) -> Option<u64> {
        Some(self.write_idle_time)
    }

    fn get_read_idle_time(&self) -> Option<u64> {
        Some(self.read_idle_time)
    }

    fn handle(&self, _context: &RpcContext, idle_data: &IdleResultData) -> RpcResult<()> {
        println!("heart idle_data: {:?}", idle_data);
        Ok(())
    }
}